package commons.base.http.client;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.http.Consts;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicNameValuePair;

import commons.base.util.StringUtil;

public class RequestBuilder {

	private String method;
	private String uri;
	private Map<String, String> headerMap = new HashMap<String, String>();
	private List<NameValuePair> form = new ArrayList<NameValuePair>();
	private String bodyString;
	
	private int localPort = 0;
	private String localHost;
	private ThreadPoolHttpClient threadPoolHttpClient;
	
	public RequestBuilder useGetMethod() {
		this.method = "get";
		return this;
	}
	public RequestBuilder usePostMethod() {
		this.method = "post";
		return this;
	}
	public RequestBuilder setUri(String uri) {
		this.uri = uri;
		return this;
	}
	
	public RequestBuilder addHeader(String name, String value){
		headerMap.put(name, value);
		return this;
	}
	
	public RequestBuilder addFormField(String name, String value){
		form.add(new BasicNameValuePair(name, value));
		return this;
	}
	
	public RequestBuilder setBodyString(String bodyString) {
		this.bodyString = bodyString;
		return this;
	}

	public RequestBuilder setLocalPort(int localPort) {
		this.localPort = localPort;
		return this;
	}

	public RequestBuilder setLocalHost(String localHost) {
		this.localHost = localHost;
		return this;
	}

	public RequestBuilder setThreadPoolHttpClient(ThreadPoolHttpClient threadPoolHttpClient) {
		this.threadPoolHttpClient = threadPoolHttpClient;
		return this;
	}
	
	private boolean isGetRequest(){
		return method.equals("get");
	}

	public HttpUriRequest build(){
		HttpUriRequest request = null;
		
		if(isGetRequest()){
			request = new HttpGet(buildGetUri());
		}else{
			request = new HttpPost(uri);
		}
		
		// add header
		if(!headerMap.containsKey("Connection")){
			request.addHeader("Connection", "close");
		}
		for(Map.Entry<String, String> entry : headerMap.entrySet()){
			request.addHeader(entry.getKey(), entry.getValue());
		}
		
		// add body
		if(!isGetRequest()){
			if(bodyString != null){
				((HttpPost)request).setEntity(new StringEntity(bodyString, Consts.UTF_8));
			}else{
				if(!form.isEmpty()){
					((HttpPost)request).setEntity(new UrlEncodedFormEntity(form, Consts.UTF_8));
				}
			}
		}
		
		return request;
	}
	
	private String buildGetUri(){
		StringBuilder sb = new StringBuilder();
		if(form != null){
			Iterator<? extends NameValuePair> it = form.iterator();
			while(it.hasNext()){
				NameValuePair nameValuePair = it.next();
				sb.append(nameValuePair.getName()).append("=").append(nameValuePair.getValue()).append("&");
			}
		}
		
		if(sb.length() > 0){
			sb = StringUtil.compareAndDeleteLastChar(sb, '&');
			if(uri.indexOf('&') != -1){//已经有参数
				uri += "&" + sb.toString();
			}else{
				uri +=	"?" + sb.toString();
			}
		}
		
		return uri;
	}
	
	public Content execute() throws ClientProtocolException, IOException{
		BasicHttpClient httpClient = null;
		try{
			httpClient = new BasicHttpClient(localHost, localPort);
			return Content.get(httpClient.execute(build()));
		}finally {
			if(httpClient != null) httpClient.shutdown();
		}
	}
	
	public void execute(FutureCallback<Content> callback){
		threadPoolHttpClient.execute(build(), callback);
	}
}
